package org.sfx.apps

import scala.collection.immutable._
import scala.collection.generic.GenericTraversableTemplate
import scala.collection.LinearSeqOptimized
import scala.collection.generic.GenericCompanion
import scala.collection.generic.SeqFactory
import scala.collection.mutable.Builder

abstract class TrackedList[+A] extends LinearSeq[A] 
                                  with Product 
                                  with GenericTraversableTemplate[A, TrackedList]
                                  with LinearSeqOptimized[A, TrackedList[A]] {
  override def companion: GenericCompanion[TrackedList] = TrackedList
  def head: A
  def tail: TrackedList[A]
  def isEmpty: Boolean
  def untracked: List[A]
  def ::[B >: A] (x: B): TrackedList[B] = org.sfx.apps.::(x, this)
  
  //override def take(n: Int): TrackedList[A] = TrackedListTake[A](this, n)

  override def drop(n: Int): TrackedList[A] = {
    TrackedListDrop[A](this, n)
  }

  //override def reverse: TrackedList[A] = TrackedListReverse[A](this)
}

case class ::[A](private var hd: A, private[apps] var tl: TrackedList[A]) extends TrackedList[A] {
  override def head: A = hd
  override def tail: TrackedList[A] = tl
  override def isEmpty: Boolean = false
  override def untracked: List[A] = hd :: tl.untracked
}

/*case class TrackedListReverse[A](original: TrackedList[A]) extends TrackedList[A] {
  lazy val replacement: List[A] = original.untracked.reverse
  override def head: A = replacement.head
  override def tail: TrackedList[A] = replacement.tail
  override def isEmpty: Boolean = false
  override def untracked: List[A] = replacement
}*/

/*case class TrackedListTakeN[A](original: TrackedList[A], n: Int) extends TrackedList[A] {
  lazy val replacement: List[A] = original.untracked.take(n)
  override def head: A = replacement.head
  override def tail: TrackedList[A] = {
    if (n > 0) {
      TrackedListTake[A]()
    }
  }
  override def isEmpty: Boolean = false
  override def untracked: List[A] = replacement
}*/

case class TrackedListDrop[A](original: TrackedList[A], n: Int) extends TrackedList[A] {
  lazy val replacement: List[A] = original.untracked.drop(n)
  override def head: A = replacement.head
  override def tail: TrackedList[A] = this.drop(1)
  override def drop(m: Int): TrackedList[A] = {
    TrackedListDrop[A](original, m + n)
  }
  override def isEmpty: Boolean = replacement.isEmpty
  override def untracked: List[A] = replacement
  override def toString(): String = "TrackedListDrop[A](" + original + ", " + n + ")"
}

case class TrackedListWrapper[A](list: List[A]) extends TrackedList[A] {
  override def head: A = list.head
  override def tail: TrackedList[A] = TrackedListWrapper[A](list.tail)
  override def isEmpty: Boolean = list.isEmpty
  override def untracked: List[A] = list
}



case object TrackedListNil extends TrackedList[Nothing] {
  override def isEmpty = true
  override def head: Nothing =
    throw new NoSuchElementException("head of empty list")
  override def tail: TrackedList[Nothing] =
    throw new UnsupportedOperationException("tail of empty list")
  override def untracked: List[Nothing] = Nil
  // Removal of equals method here might lead to an infinite recursion similar to IntMap.equals.
  override def equals(that: Any) = that match {
    case that1: collection.Seq[_] => that1.isEmpty
    case _ => false
  }
}

object TrackedList extends SeqFactory[TrackedList] {
  def apply[A](list: List[A]): TrackedList[A] = TrackedListWrapper[A](list)

  def newBuilder[A]: Builder[A, TrackedList[A]] = new TrackedListBuffer[A]
}

object Abc {

}
